package leetcode_41_60;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class solveNQueens_51 {
    /*
    皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
    将 n 个皇后放置在 n×n 的棋盘上，并且使皇后彼此之间不能相互攻击。
    返回所有不同的 n 皇后问题 的解决方案
    1 <= n <= 9
     */
    /*
        思路是维护一个n*n的二维数组
        1 表示无法继续放
        0 表示可以放
        2 表示Q
        递归回溯 , 第n个皇后只需要遍历放置第n行

        太慢了，16ms  5%
         */
    public List<List<String>> solveNQueens(int n) {
        int [][]chessboard=new int[n][n];
        dfs(chessboard, 0);
        return ans;
    }

    public List<List<String>> ans = new ArrayList<>();

    public void dfs(int[][] chessboard, int row) {
        if (row >= chessboard.length ) { //能运行到这里就说明条件都满足
            //放完了
            formatChessboard(chessboard);
            return;
        }
        //第 row 行数组
        int[] line = chessboard[row];
        for (int j = 0; j < line.length; j++) {
            if (line[j] == 1) {
                //无法放置
                continue;
            }
            //可以放置
            line[j] = 2;
            //刷新grid, 把 不能放的位置变成1
            int[][] copy = refreshChessboard(chessboard, row, j);
            //向第i + 1 行递归
            dfs(copy, row + 1);
            //回溯 把当前位置置为0
            line[j] = 0;
        }
        //没有位置可以放
    }

    //要重新成一个新的chessboard，才能不影响下次回溯
    //(i, j)为Q位置
    public int[][] refreshChessboard(int[][] chessboard, int i, int j) {
        int[][] copy = Arrays.stream(chessboard)
                .map(int[]::clone)
                .toArray(int[][]::new);
        for (int k = i + 1; k < chessboard.length; k++) {         //只用管下边的行即可
            for (int l = 0; l < chessboard[i].length; l++) {//列
                if (l == j) {                       //同一列
                    copy[k][l] = 1;
                }
                if (Math.abs(i - k) == Math.abs(j - l)) {      //向下的斜线
                    //行与Q所在行的位置差等于列与Q所在列的位置差相等
                    copy[k][l] = 1;
                }
            }
        }
        return copy;
    }

    /**
     * 将数组转化为需要的棋盘形式
     * @param chessboard
     */
    public void formatChessboard(int[][] chessboard) {
        List<String> partRes = new ArrayList<>();
        for (int i = 0; i < chessboard.length; i++) {
            int[] line = chessboard[i];
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < line.length; j++) {
                if (line[j] == 0 || line[j] == 1) {
                    sb.append(".");
                }else {
                    sb.append("Q");
                }
            }
            partRes.add(sb.toString());
        }
        ans.add(partRes);
    }


    /**
     * 3ms
     * 官解
     * @param n
     * @return
     */
    public List<List<String>> solveNQueens2(int n) {
        //array[i]表示第i行对应皇后列的下标
        int[] array = new int[n];
        //返回的集合
        List<List<String>> lists = new ArrayList<>();
        //从第一行开始从头开始遍历
        dfs(0,array,lists,n);
        return lists;
    }
    public void dfs(int row,int[] array,List<List<String>> lists,int n){
        //每一行都有对应的皇后，此时满足条件，将Q添加进数组中，添加结果返回
        if(row == n){
            List<String> list = new ArrayList<>();
            for(int i = 0;i<n;i++){
                char[] i_row = new char[n];
                //先将每一行置为'.'---即....
                Arrays.fill(i_row,'.');
                //第i行中对应皇后的列置为'Q'---即...Q
                i_row[array[i]] = 'Q';
                //将该行添加到list中
                list.add(new String(i_row));
            }
            lists.add(new ArrayList<>(list));
            return;
        }

        //从每一行开始遍历，这样能保证行是绝对不会发生冲突的，因为他是递增的
        for(int i = 0;i<n;i++){
            //将第x行设置为第i列
            array[row] = i;
            //判断位置是否冲突，flag变量控制循环跳出
            boolean flag = true;
            //j<row，即判断当前行的Q与之前的Q是否冲突
            for(int j = 0;j<row;j++){
                //array[j] == array[row]判断   同一列
                //Math.abs(row-j) == Math.abs(array[row]-array[j])  判断  正负对角线上
                if(array[j] == array[row] || Math.abs(row-j) == Math.abs(array[row]-array[j])){
                    //发生冲突，则直接跳出循环
                    flag = false;
                    break;
                }
            }
            //当前列存在冲突，寻找下一列
            if(!flag)continue;
            //不冲突，则放下一个皇后 x+1
            dfs(row+1,array,lists,n);
        }
    }

}
